package com.resource.base.config.jwt;

import com.resource.base.config.MyProperties;
import com.resource.project.service.system.service.impl.UserService;
import io.jsonwebtoken.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Component
public class TokenProvider {
    private static final String EXPIRATION = "expiration";
    private static final String PRINCIPAL = "principal";
    private final Logger log = LoggerFactory.getLogger(TokenProvider.class);
    private final MyProperties jinesProperties;
    private final UserService userDetailsService;
    private String secretKey;
    private long tokenValidityInMilliseconds;
    private long tokenValidityInMillisecondsForRememberMe;

    public TokenProvider(MyProperties jinesProperties, UserService userDetailsService) {
        this.jinesProperties = jinesProperties;
        this.userDetailsService = userDetailsService;
    }

    @PostConstruct
    public void init() {
        this.secretKey = this.jinesProperties.getSecurity().getAuthentication().getJwt().getSecret();
        this.tokenValidityInMilliseconds = 1000L * this.jinesProperties.getSecurity().getAuthentication().getJwt().getTokenValidityInSeconds();
        this.tokenValidityInMillisecondsForRememberMe = 1000L * this.jinesProperties.getSecurity().getAuthentication().getJwt().getTokenValidityInSecondsForRememberMe();
    }

    private Claims getClaimsFromToken(String token) {
        Claims claims;
        try {
            claims = (Claims)Jwts.parser().setSigningKey(this.secretKey).parseClaimsJws(token).getBody();
        } catch (Exception var4) {
            claims = null;
        }

        return claims;
    }

    private String generateToken(String subject, Map<String, Object> claims, long expiration) {
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(subject)
                .setId(UUID.randomUUID().toString())
                .setIssuedAt(new Date())
                .setExpiration(this.generateExpirationDate(expiration))
                .compressWith(CompressionCodecs.DEFLATE)
                .signWith(SignatureAlgorithm.HS512, this.secretKey)
                .compact();
    }

    private Date generateExpirationDate(long expiration) {
        return new Date(System.currentTimeMillis() + expiration * 1000L);
    }

    public String createToken(final Authentication authentication, Boolean rememberMe) {
        long expiration = rememberMe ? this.tokenValidityInMillisecondsForRememberMe : this.tokenValidityInMilliseconds;
        return this.generateToken(authentication.getName(), new HashMap<String, Object>() {
            private static final long serialVersionUID = 1L;

            {
                this.put(PRINCIPAL, authentication.getName());
            }
        }, expiration);
    }

    public Authentication getAuthentication(String token) {
        Claims claims = this.getClaimsFromToken(token);
        UserDetails userDetails = this.userDetailsService.loadUserByUsername((String) claims.get("principal"));
        return new UsernamePasswordAuthenticationToken(userDetails, token, userDetails.getAuthorities());
    }

    public Date getExpirationDateFromToken(String token) {
        Date expiration;
        try {
            Claims claims = this.getClaimsFromToken(token);
            expiration = claims.getExpiration();
        } catch (Exception var4) {
            expiration = null;
        }

        return expiration;
    }

    public long getExpirationDateSecondsFromToken(String token) {
        return (this.getExpirationDateFromToken(token).getTime() - (new Date()).getTime()) / 1000L;
    }

    public String refreshToken(String token) {
        String refreshedToken;
        try {
            Claims claims = this.getClaimsFromToken(token);
            refreshedToken = this.generateToken(claims.getSubject(), claims, (Long)claims.get("expiration"));
        } catch (Exception var4) {
            refreshedToken = null;
        }

        return refreshedToken;
    }

    public Boolean isTokenExpired(String token) {
        Date expiration = this.getExpirationDateFromToken(token);
        return expiration.before(new Date());
    }

    public boolean validateToken(String authToken) {
        try {
            Jwts.parser().setSigningKey(this.secretKey).parseClaimsJws(authToken);
            return true;
        } catch (SignatureException var3) {
            this.log.info("Invalid JWT signature.");
            this.log.trace("Invalid JWT signature trace: {}", var3);
        } catch (MalformedJwtException var4) {
            this.log.info("Invalid JWT token.");
            this.log.trace("Invalid JWT token trace: {}", var4);
        } catch (ExpiredJwtException var5) {
            this.log.info("Expired JWT token.");
            this.log.trace("Expired JWT token trace: {}", var5);
        } catch (UnsupportedJwtException var6) {
            this.log.info("Unsupported JWT token.");
            this.log.trace("Unsupported JWT token trace: {}", var6);
        } catch (IllegalArgumentException var7) {
            this.log.info("JWT token compact of handler are invalid.");
            this.log.trace("JWT token compact of handler are invalid trace: {}", var7);
        }

        return false;
    }
}
